package com.bulunsh.wensen.distributed.oauth.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;

@Configuration
@EnableAuthorizationServer  //标记我是授权服务
public class AuthorizationServer extends AuthorizationServerConfigurerAdapter {


    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Autowired
    private AuthenticationManager authenticationManager;



    //1.配置客户端详情  谁来申请令牌，在这里配置支持哪些客户端
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.inMemory()//使用内存存储
                .withClient("c1") //客户端id
                .secret("secret")//客户端密码
                .resourceIds("res1")//可以访问的资源列表
                //允许的5种授权类型
                .authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
                .scopes("all")//允许的授权范围
                .autoApprove(false)//如果是授权码模式 false 跳转到授权页面，true 不跳
                .redirectUris("https://www.baidu.com");//验证的回调地址
    }


    //2.令牌服务
    @Bean
    public AuthorizationServerTokenServices tokenServices() {
        //新建一个令牌服务
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setClientDetailsService(clientDetailsService);//根据上面配置的客户端信息服务 ，放进来
        defaultTokenServices.setSupportRefreshToken(true);//配置是否产生刷新令牌
        defaultTokenServices.setTokenStore(tokenStore);//令牌存储策略 这里放生成的token,一般是通过redis生成的
        defaultTokenServices.setAccessTokenValiditySeconds(7200);//令牌有效时间
        defaultTokenServices.setRefreshTokenValiditySeconds(259200);//刷新令牌有效时间3天
        return defaultTokenServices;
        //3.令牌有了以后，需要暴露端点
    }

    //3.配置令牌访问端点和令牌服务（怎么发放和怎么生成）
    //这里配置令牌的访问端点  令牌服务（怎么发放和怎么生成）
    //这里有5种,一般只用前四种 authenticationManager 密码认证
    //userDetailsService 这个需要自己重写userDetailsService的实现
    //authorizationCodeServices 授权码
    //implicitGrantService  隐式
    //tokenGranter 授权自己完全掌控，自己找活干吗
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints
                .authenticationManager(authenticationManager)//密码模式需要
                .authorizationCodeServices(authorizationCodeServices)//授权码模式需要
                .tokenServices(tokenServices())//令牌管理服务必须需要的
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);//允许post 提交

    }

    //4.配置令牌端点的安全策略  像r/r1 必须验证才能访问就是安全约束
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        //框架有几个自带的url /oauth/authorize  /oauth/token 等等
        security
                .tokenKeyAccess("permitAll()")   //oauth/token_key 公开不拦截
                .checkTokenAccess("permitAll()")//oauth/check_token 公开不拦截
                .allowFormAuthenticationForClients();//表单验证，申请令牌

        //配置好这个，再配置web安全配置就可以了 webSecurityConfig
    }

    @Bean
    public AuthorizationCodeServices authorizationCodeServices(){//设置授权码的模式的授权码如何存取，暂时用内存方式
        return new InMemoryAuthorizationCodeServices();
    }


}
